package com.ray.system.api;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.ray.common.Perifx;
import com.ray.common.SysConstant;
import com.ray.common.SysMsgCodeConstant;
import com.ray.system.builder.LoginBuilder;
import com.ray.system.builder.LoginLogBuilder;
import com.ray.system.builder.LoginUserBuilder;
import com.ray.system.builder.MenuTreeBuilder;
import com.ray.system.check.AppCheck;
import com.ray.system.check.ImageCheck;
import com.ray.system.check.LoginCheck;
import com.ray.system.check.UserCheck;
import com.ray.system.service.*;
import com.ray.system.service.compose.CompanyService;
import com.ray.system.service.compose.RedisService;
import com.ray.system.service.compose.UserService;
import com.ray.system.table.TreeUtil;
import com.ray.system.table.entity.*;
import com.ray.system.table.params.base.LoginParams;
import com.ray.system.table.vo.company.CompanyVO;
import com.ray.system.table.vo.menu.AuthVO;
import com.ray.system.table.vo.menu.MenuTreeVO;
import com.ray.util.ValidateCode;
import com.ray.validate.support.utils.ValidateUtil;
import com.ray.woodencreate.beans.LoginUser;
import com.ray.woodencreate.exception.BusinessExceptionFactory;
import com.ray.woodencreate.result.MsgCodeConstant;
import com.ray.woodencreate.result.Result;
import com.ray.woodencreate.result.ResultFactory;
import com.ray.woodencreate.util.IPUtil;
import com.ray.woodencreate.util.LogInUserUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Base64Utils;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author bo shen
 * @Description: 基础服务
 * @Class: BaseApi
 * @Package com.ray.system.api
 * @date 2020/5/29 9:08
 * @company <p>Ray快速开发平台</p>
 * @updateRecord time(修改时间)  author(修改人)   desc(修改内容)
 */
@Service
@Slf4j
public class BaseApi {

    @Autowired
    private RedisService redisService;
    @Autowired
    private SysLoginService sysLoginService;
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SysUserCompanyService sysUserCompanyService;
    @Autowired
    private SysCompanyService sysCompanyService;
    @Autowired
    private UserService userService;
    @Autowired
    private CompanyService companyService;
    @Autowired
    private SysLoginLogService sysLoginLogService;
    @Autowired
    private SysAppService sysAppService;
    /*** 图片验证码**/
    private static final ValidateCode VALIDATE_CODE = new ValidateCode(100, 40, 4, 120);

    /**
     * 获取图片验证码
     *
     * @param request
     * @return
     */
    public Result<String> queryImageCode(HttpServletRequest request) {
        VALIDATE_CODE.createCode();
        //图片验证码
        String capText = VALIDATE_CODE.getCode();
        //session
        String sessionId = IPUtil.getIpAddress(request);
        log.info("sessionId:{},验证码:{}", sessionId, capText);
        //图片验证码写入redis
        redisService.setValue(sessionId, capText, SysConstant.IMAGE_TIME);
        BufferedImage bi = VALIDATE_CODE.getBuffImg();
        // 字节输出流
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        try {
            ImageIO.write(bi, "jpg", byteArrayOutputStream);
            String imageData = Base64Utils.encodeToString(byteArrayOutputStream.toByteArray());
            return ResultFactory.createSuccessResult(MsgCodeConstant.Success.SUC00000002, imageData);
        } catch (IOException e) {
            log.info("创建图片验证码异常:{}", e.getLocalizedMessage(), e);
            return ResultFactory.createErrorResult(MsgCodeConstant.Error.ERR00000001);
        } finally {
            try {
                byteArrayOutputStream.close();
            } catch (IOException e) {
                log.error("ByteArrayOutputStream 关闭异常", e);
            }
        }
    }

    /**
     * 用户登录
     *
     * @param loginParams
     * @param request
     * @return
     */
    @Transactional
    public Result<LoginUser> login(LoginParams loginParams, HttpServletRequest request) {
        ValidateUtil.validate(loginParams);
        //session
        String sessionId = IPUtil.getIpAddress(request);
        //图片验证码写入redis
        String capText = redisService.getValue(sessionId);
        log.info("sessionId:{},验证码:{}", sessionId, capText);
        new ImageCheck(capText).checkNull(MsgCodeConstant.Error.ERR88000013).checkSam(loginParams.getImageCode(), MsgCodeConstant.Error.ERR88000013);
        String sessionKey = IdUtil.fastSimpleUUID();
        log.info("sessionKey:{}", sessionKey);
        //获取系统信息
        SysApp sysApp = sysAppService.queryAppByAppKey(loginParams.getAppKey());
        new AppCheck(sysApp).checkNull(SysMsgCodeConstant.Error.ERR10000013);
        //校验
        SysLogin sysLogin = sysLoginService.queryByLogin(loginParams.getLoginName(), loginParams.getPassword());
        new LoginCheck(sysLogin).checkNull(MsgCodeConstant.Error.ERR88000014);
        SysUser sysUser = sysUserService.queryUserByUserCodeForLogin(sysLogin.getUserCode());
        new UserCheck(sysUser).checkNull(MsgCodeConstant.Error.ERR88000014);
        //默认登陆公司
        String defaultCompanyCode = sysLogin.getCompanyCode();
        //查询用户所属的公司
        List<SysUserCompany> userCompanies = sysUserCompanyService.listByLogin(sysUser.getUserCode());
        LoginUserBuilder loginUserBuilder = new LoginUserBuilder();
        List<String> companyCodes = userCompanies.stream().map(sysUserCompany -> {
            return sysUserCompany.getComapnyCode();
        }).collect(Collectors.toList());
        if (ObjectUtil.isNotEmpty(companyCodes)) {
            //判断默认公司是否在当前公司下
            if (!companyCodes.contains(defaultCompanyCode)) {
                defaultCompanyCode = companyCodes.get(0);
            }
            //所属公司
            List<SysCompany> sysCompanies = sysCompanyService.queryCompanyByCompanyCodesForLogin(companyCodes);
            loginUserBuilder.append(sysCompanies);
        } else {
            //没有所属公司
            defaultCompanyCode = "";
        }


        loginUserBuilder.append(sysUser).appnedSessionKey(sessionKey).append(sysApp);
        //获取公司信息
        if (StrUtil.isNotBlank(defaultCompanyCode)) {
            SysCompany sysCompany = sysCompanyService.queryCompanyByLogin(defaultCompanyCode);
            loginUserBuilder.append(sysCompany);
            //获取部门信息
            SysOrganization sysOrganization = companyService.getOrganizationForLogin(sysLogin.getUserCode(), defaultCompanyCode);
            if (ObjectUtil.isNotNull(sysOrganization)) {
                loginUserBuilder.appendDept(sysOrganization);
            } else {
                loginUserBuilder.appendDept(sysCompany);
            }
            //获取职位信息
            SysPosition sysPosition = userService.queryPositionByLogin(sysLogin.getUserCode(), defaultCompanyCode);
            loginUserBuilder.append(sysPosition);
        }
        redisService.setValue(sessionKey, JSON.toJSONString(loginUserBuilder.bulid()), SysConstant.LOGIN_TIME);
        //插入登录日志
        LoginLogBuilder loginLogBuilder = new LoginLogBuilder();
        loginLogBuilder.append(sysUser).appendCreate(loginUserBuilder.bulid());
        sysLoginLogService.save(loginLogBuilder.bulid());
        //回写登录信息
        LoginBuilder loginBuilder = new LoginBuilder();
        loginBuilder.appendCode(sysLogin.getUserCode()).appendSessionKey(sessionKey)
                .appendComapnyCode(defaultCompanyCode)
                .appendEdit(loginUserBuilder.bulid());
        sysLoginService.edit(loginBuilder.bulid(), loginUserBuilder.bulid());
        return ResultFactory.createSuccessResult(MsgCodeConstant.Success.SUC00000002, loginUserBuilder.bulid());
    }


    /**
     * 切换公司
     *
     * @param companyCode
     * @return
     */
    @Transactional
    public Result<LoginUser> switchCompany(String companyCode) {
        ValidateUtil.hasLength(companyCode, "参数[companyCode]不能为空");
        LoginUser loginUser = LogInUserUtil.get();
        //查询用户所属的公司
        List<SysUserCompany> userCompanies = sysUserCompanyService.listByLogin(loginUser.getUserCode());
        List<String> companyCodes = userCompanies.stream().map(sysUserCompany -> {
            return sysUserCompany.getComapnyCode();
        }).collect(Collectors.toList());
        if (ObjectUtil.isNotEmpty(companyCodes)) {
            //判断默认公司是否在当前公司下
            if (!companyCodes.contains(companyCode)) {
                log.info("无当前切换公司权限,参数:{}", companyCode);
                throw BusinessExceptionFactory.newException(SysMsgCodeConstant.Error.ERR10000012);
            }
        }
        LoginUserBuilder loginUserBuilder = new LoginUserBuilder();
        loginUserBuilder.append(loginUser);
        SysCompany sysCompany = sysCompanyService.queryCompanyByLogin(companyCode);
        loginUserBuilder.append(sysCompany);
        //获取部门信息
        SysOrganization sysOrganization = companyService.getOrganizationForLogin(loginUser.getUserCode(), companyCode);
        if (ObjectUtil.isNotNull(sysOrganization)) {
            loginUserBuilder.appendDept(sysOrganization);
        } else {
            loginUserBuilder.appendDept(sysCompany);
        }
        //获取职位信息
        SysPosition sysPosition = userService.queryPositionByLogin(loginUser.getUserCode(), companyCode);
        loginUserBuilder.append(sysPosition);
        redisService.setValue(loginUser.getToken(), JSON.toJSONString(loginUserBuilder.bulid()), SysConstant.LOGIN_TIME);
        return ResultFactory.createSuccessResult(MsgCodeConstant.Success.SUC00000002, loginUserBuilder.bulid());
    }

    /**
     * 当前登陆人的菜单权限
     ** @return
     */
    public Result<List<MenuTreeVO>> leftMenu() {
        LoginUser loginUser = LogInUserUtil.get();
        //获取系统信息
        SysApp sysApp = sysAppService.queryAppByAppKey(loginUser.getAppKey());
        new AppCheck(sysApp).checkNull(SysMsgCodeConstant.Error.ERR10000013);
        //菜单权限
        List<SysMenu> sysMenus = userService.leftMenu(sysApp.getAppCode(), loginUser);
        List<MenuTreeVO> menuTreeList = sysMenus.stream().map(sysMenu -> {
            return new MenuTreeBuilder().append(sysMenu).bulid();
        }).sorted(Comparator.comparingInt(menu ->{
            return ObjectUtil.isNotNull(menu.getIndexSort())? menu.getIndexSort():0;
        })).collect(Collectors.toList());

        List<MenuTreeVO> treeVOS =  TreeUtil.bulid(menuTreeList, SysConstant.MENU_ROOT);
        //功能权限
        List<SysMenu> sysFun = userService.leftFun(sysApp.getAppCode(), loginUser);
        sysFun.forEach(sysMenu -> {
            treeVOS.add(new MenuTreeBuilder().append(sysMenu).bulid());
        });
        return ResultFactory.createSuccessResult(MsgCodeConstant.Success.SUC00000002,treeVOS );
    }

    /**
     * 当前登陆人的菜单权限
     * @return
     */
    public Result<Set<String>> auth() {
        LoginUser loginUser = LogInUserUtil.get();
        //获取系统信息
        SysApp sysApp = sysAppService.queryAppByAppKey(loginUser.getAppKey());
        new AppCheck(sysApp).checkNull(SysMsgCodeConstant.Error.ERR10000013);
        //按钮请求权限
        final Set<String> authUrl = new HashSet<>();

        //按钮权限
        List<SysMenu> sysBtn = userService.leftBtn(sysApp.getAppCode(), loginUser);
        Set<String> authCode = sysBtn.stream().map(sysMenu -> {
            authUrl.add(sysMenu.getAuthUrl());
            return sysMenu.getPermission();
        }).collect(Collectors.toSet());

        //功能权限
        List<SysMenu> sysFun = userService.leftFun(sysApp.getAppCode(), loginUser);
        sysFun.forEach(sysMenu -> {
            authUrl.add(sysMenu.getAuthUrl());
            authCode.add(sysMenu.getPermission());
        });
        //权限写入缓存
        authCode.add("yes");
        redisService.setValue(String.format("%s%s", Perifx.AUTH, loginUser.getToken()), JSON.toJSONString(authUrl), SysConstant.LOGIN_TIME);
        return ResultFactory.createSuccessResult(MsgCodeConstant.Success.SUC00000002, authCode);
    }


    /**
     * 退出登录
     *
     * @return
     */
    public Result<String> logOut() {
        LoginUser loginUser = LogInUserUtil.get();
        redisService.removeValue(String.format("%s%s", Perifx.AUTH, loginUser.getToken()));
        redisService.removeValue(loginUser.getToken());
        return ResultFactory.createSuccessResult(MsgCodeConstant.Success.SUC00000001);
    }


}
